﻿#region 文件信息

/*----------------------------------------------------------------
//
// 文件名称：
// 文件功能描述：
// 设计要求：
//
// 文 件 名：    VampirewalCoreConfig
// 创建者：      杨程
// 创建日期：	    2023/1/28 12:17:34

//----------------------------------------------------------------*/

#endregion

namespace Vampirewal.Core.Components;

/// <summary>
/// 配置文件
/// </summary>
[Obsolete("20250620 废弃，使用IVampirewalCoreAppConfig",true)]
internal sealed class VampirewalCoreConfig
{
    private string JsonStr { get; set; }
    internal JObject JObject { get; set; }

    private string ConfigPath { get; set; }

    /// <summary>
    ///
    /// </summary>
    internal VampirewalCoreConfig(string path)
    {
        //构造函数
        ConfigPath = path;
    }

    /// <summary>
    /// 获取配置
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    internal T GetOptions<T>() where T : IOptions
    {
        Type type = typeof(T);

        JToken jToken = JObject[type.Name];

        string token = JsonConvert.SerializeObject(jToken);

        T t = JsonConvert.DeserializeObject<T>(token);

        return t?? throw new Exception("配置文件中无该节点数据！");
    }

    /// <summary>
    /// 根据A:B:C这样的来获取数据
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    internal T GetOptionsValue<T>(string key)
    {
        var keyArray = key.Split(":".ToArray());
        var firstKey = keyArray.FirstOrDefault();
        var otherKey = keyArray.Skip(1);
        JToken jToken = JObject[firstKey];
        foreach (var item in otherKey)
        {
            jToken = jToken[item];
        }

        string token = JsonConvert.SerializeObject(jToken);

        return JsonConvert.DeserializeObject<T>(token); ;
    }

    /// <summary>
    /// 保存配置
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="Options"></param>
    internal void SaveOptions<T>(T Options) where T : IOptions
    {
        Type type = typeof(T);

        JObject[type.Name] = JObject.Parse(JsonConvert.SerializeObject(Options));

        SaveConfig();
    }

    /// <summary>
    /// 完整保存配置文件
    /// </summary>
    internal void SaveConfig()
    {
        var formatStr = JsonHelper.FormatJsonString(JsonConvert.SerializeObject(JObject));

        File.Delete(ConfigPath);

        File.AppendAllText(ConfigPath, formatStr);
    }

    /// <summary>
    /// 在传入的目标路径下创建一个新的配置文件
    /// </summary>
    private void CreateNewConfig()
    {
        string DevPath = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.FullName;

        string _configPath = $"{DevPath}\\AppConfig.json";

        JObject = new JObject();

        foreach (var item in OptionsList)
        {
            Type type = item.GetType();
            object obj = Activator.CreateInstance(type);
            string token = JsonConvert.SerializeObject(obj);
            JObject.TryAdd(type.Name, JObject.Parse(token));
        }

        var formatStr = JsonHelper.FormatJsonString(JsonConvert.SerializeObject(JObject));

        File.Delete(_configPath);

        File.AppendAllText(_configPath, formatStr);
    }

    /// <summary>
    /// 简单加载一下模块程序集，方便后续反射的时候，找到这些程序集
    /// </summary>
    /// <exception cref="Exception"></exception>
    private void LoadModules()
    {
        GetOptions<AppBaseOptions>().ModulesPath.ForEach(f =>
        {
            try
            {
                #region 20250303 如果模块的文件地址是绝对地址还好，相对地址的话，这里会报错。顾这样修改一下。
                string filePath = string.Empty;

                if (Path.IsPathRooted(f))
                {
                    filePath = Path.GetFullPath(f);
                }
                else
                {
                    filePath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, f));
                } 
                #endregion

                Assembly ass = Assembly.LoadFile(filePath);
            }
            catch
            {
                throw new Exception($"无法加载该DLL：{f}");
            }
        });

        var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalModuleBootStartup))).ToArray();

        Dictionary<string, IVampirewalModuleBootStartup> moduleDic = new Dictionary<string, IVampirewalModuleBootStartup>();

        foreach (var v in types)
        {
            var obj = Activator.CreateInstance(v) as IVampirewalModuleBootStartup;

            //obj.LoadModuleOption(OptionsList);

            if(!moduleDic.TryAdd(v.Name, obj))
            {
                throw new Exception($"模块名称：{v.Name},重复！");
            }
        }

        VampirewalCoreContext.GetInstance().AddContext("ModuleDic", moduleDic);
    }

    #region 新代码

    internal List<IOptions> OptionsList { get; set; } = new List<IOptions>();

    /// <summary>
    /// 读取配置文件
    /// </summary>
    /// <exception cref="ArgumentException"></exception>
    /// <exception cref="Exception"></exception>
    internal void LoadConfig()
    {
        //1、先判断一下启动程序的路径下有没有这个配置文件，没有就按照添加进来的配置项创建对应的json配置文件

#if DEBUG
        if (!File.Exists(ConfigPath))
        {
            CreateNewConfig();
            throw new ArgumentException("Config路径不存在,已在VS中当前项目的根路径下创建了Config文件!请修改属性为内容和较新则复制！");
        }
#endif

        //2、已经读取到了配置文件
        JsonStr = JsonHelper.Readjson(ConfigPath);

        if (string.IsNullOrEmpty(JsonStr))
        {
            throw new Exception("配置文件无内容");
        }

        //3、转成JObject
        JObject = JObject.Parse(JsonStr);
        bool IsSave = false;

        //5、20250303 这里需要调整到调用，因为模块里面也可能涉及到配置文件的加载
        LoadModules();

        //4、将每一个传进来的配置项检查一下，读取到的json中有没有对应的键值
        foreach (var item in OptionsList)
        {
            Type type = item.GetType();

            object obj = null;
            try
            {
                JToken jToken = JObject[type.Name];

                string token = JsonConvert.SerializeObject(jToken);
                //直接将对应的token转成这个obj看是不是null
                obj = JsonConvert.DeserializeObject(token);

                VampirewalCoreContext.GetInstance().AddContext(type.Name, token);
            }
            catch
            {
                //异常什么的直接吞掉吧
            }
            finally
            {
                //如果obj为null说明配置文件中并没有这个配置项的对应键值，那么在这里添加进去，并把IsSave标记为true，方便后面生成对应的json文件
                if (obj == null)
                {
                    JObject[type.Name] = JObject.Parse(JsonConvert.SerializeObject(Activator.CreateInstance(type)));
                    IsSave = true;
                }
            }
        }

        if (IsSave)
        {
            string DevPath = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory).Parent.Parent.Parent.FullName;

            var formatStr = JsonHelper.FormatJsonString(JsonConvert.SerializeObject(JObject));

            FileInfo info = new FileInfo(ConfigPath);
            var filename = info.Name;

            string _configPath = $"{DevPath}\\{filename}";

            File.Delete(_configPath);

            File.AppendAllText(_configPath, formatStr);

            //因为新增了对应的配置内容，这里按道理来说是不能进来的，能进来的话，就是新增了，所以直接抛个异常中断程序
            throw new Exception($"已重新添加了配置信息内容在{filename}中，请修改属性为内容和较新则复制！重新编译！");
        }

        
    }

    #endregion
}